"""
JSON处理工具类，提供JSON解析、查询、修改等功能
"""

import json
import os
from typing import Any, Dict, List, Union, Optional


class JsonUtils:
    """
    JSON处理工具类，提供各种JSON操作功能
    """
    
    def __init__(self, json_path: str = None, json_str: str = None):
        """
        初始化JSON处理工具

        :param json_path: JSON文件路径，可选
        :param json_str: JSON字符串，可选
        """
        self.data = None
        
        if json_path:
            self.load_from_file(json_path)
        elif json_str:
            self.load_from_string(json_str)
    
    def load_from_file(self, json_path: str) -> None:
        """
        从文件加载JSON

        :param json_path: JSON文件路径
        """
        if not os.path.exists(json_path):
            raise FileNotFoundError(f"JSON文件不存在: {json_path}")
        
        with open(json_path, 'r', encoding='utf-8') as f:
            self.data = json.load(f)
    
    def load_from_string(self, json_str: str) -> None:
        """
        从字符串加载JSON

        :param json_str: JSON字符串
        """
        self.data = json.loads(json_str)
    
    def save_to_file(self, json_path: str, indent: int = 2) -> None:
        """
        保存JSON到文件

        :param json_path: 保存路径
        :param indent: 缩进空格数
        """
        if self.data is None:
            raise ValueError("没有可保存的JSON数据")
        
        with open(json_path, 'w', encoding='utf-8') as f:
            json.dump(self.data, f, ensure_ascii=False, indent=indent)
    
    def to_string(self, indent: int = None) -> str:
        """
        将JSON数据转换为字符串

        :param indent: 缩进空格数
        :return: JSON字符串
        """
        if self.data is None:
            raise ValueError("没有可转换的JSON数据")
        
        return json.dumps(self.data, ensure_ascii=False, indent=indent)
    
    def get_value(self, key_path: Union[str, List[str]], default: Any = None) -> Any:
        """
        获取指定路径的值

        :param key_path: 键路径，可以是点分隔的字符串或列表，如 "user.name" 或 ["user", "name"]
        :param default: 默认值
        :return: 键对应的值
        """
        if self.data is None:
            return default
        
        # 处理键路径
        if isinstance(key_path, str):
            keys = key_path.split('.')
        else:
            keys = key_path
        
        current = self.data
        try:
            for key in keys:
                if isinstance(current, dict):
                    current = current[key]
                elif isinstance(current, list):
                    current = current[int(key)]
                else:
                    return default
            return current
        except (KeyError, IndexError, ValueError):
            return default
    
    def set_value(self, key_path: Union[str, List[str]], value: Any) -> bool:
        """
        设置指定路径的值

        :param key_path: 键路径，可以是点分隔的字符串或列表
        :param value: 要设置的值
        :return: 是否设置成功
        """
        if self.data is None:
            # 如果没有数据，创建一个空字典
            self.data = {}
        
        # 处理键路径
        if isinstance(key_path, str):
            keys = key_path.split('.')
        else:
            keys = key_path
        
        current = self.data
        try:
            # 遍历到倒数第二个键
            for key in keys[:-1]:
                if isinstance(current, dict):
                    if key not in current:
                        # 判断下一个键是否为数字来决定创建字典还是列表
                        try:
                            int(keys[keys.index(key) + 1])
                            current[key] = []
                        except ValueError:
                            current[key] = {}
                    current = current[key]
                elif isinstance(current, list):
                    key_index = int(key)
                    # 确保列表足够长
                    while len(current) <= key_index:
                        current.append({})
                    if key_index == len(current):
                        current.append({})
                    current = current[key_index]
            
            # 设置最后一个键的值
            last_key = keys[-1]
            if isinstance(current, dict):
                current[last_key] = value
            elif isinstance(current, list):
                last_index = int(last_key)
                # 确保列表足够长
                while len(current) <= last_index:
                    current.append(None)
                current[last_index] = value
            return True
        except (IndexError, ValueError):
            return False
    
    def find_all_keys(self, key: str) -> List[Any]:
        """
        查找所有指定键的值

        :param key: 要查找的键名
        :return: 所有匹配键的值列表
        """
        result = []
        
        def _search(obj):
            if isinstance(obj, dict):
                if key in obj:
                    result.append(obj[key])
                for v in obj.values():
                    _search(v)
            elif isinstance(obj, list):
                for item in obj:
                    _search(item)
        
        if self.data is not None:
            _search(self.data)
        
        return result
    
    def update_all_keys(self, key: str, value: Any) -> int:
        """
        更新所有指定键的值

        :param key: 要更新的键名
        :param value: 新的值
        :return: 更新的键数量
        """
        count = 0
        
        def _update(obj):
            nonlocal count
            if isinstance(obj, dict):
                if key in obj:
                    obj[key] = value
                    count += 1
                for v in obj.values():
                    _update(v)
            elif isinstance(obj, list):
                for item in obj:
                    _update(item)
        
        if self.data is not None:
            _update(self.data)
        
        return count
    
    def update_nth_key(self, key: str, value: Any, n: int) -> bool:
        """
        更新第N个指定键的值（从0开始计数）

        :param key: 要更新的键名
        :param value: 新的值
        :param n: 第N个键（从0开始）
        :return: 是否更新成功
        """
        count = 0
        
        def _update(obj):
            nonlocal count
            if isinstance(obj, dict):
                if key in obj:
                    if count == n:
                        obj[key] = value
                        return True
                    count += 1
                for v in obj.values():
                    if _update(v):
                        return True
            elif isinstance(obj, list):
                for item in obj:
                    if _update(item):
                        return True
            return False
        
        if self.data is not None:
            return _update(self.data)
        return False
    
    def delete_key(self, key_path: Union[str, List[str]]) -> bool:
        """
        删除指定路径的键

        :param key_path: 键路径
        :return: 是否删除成功
        """
        if self.data is None:
            return False
        
        # 处理键路径
        if isinstance(key_path, str):
            keys = key_path.split('.')
        else:
            keys = key_path
        
        current = self.data
        try:
            # 遍历到倒数第二个键
            for key in keys[:-1]:
                if isinstance(current, dict):
                    current = current[key]
                elif isinstance(current, list):
                    current = current[int(key)]
                else:
                    return False
            
            # 删除最后一个键
            last_key = keys[-1]
            if isinstance(current, dict) and last_key in current:
                del current[last_key]
                return True
            elif isinstance(current, list):
                last_index = int(last_key)
                if 0 <= last_index < len(current):
                    del current[last_index]
                    return True
            return False
        except (KeyError, IndexError, ValueError):
            return False
    
    def add_to_list(self, key_path: Union[str, List[str]], value: Any) -> bool:
        """
        向指定路径的列表添加元素

        :param key_path: 列表路径
        :param value: 要添加的值
        :return: 是否添加成功
        """
        if self.data is None:
            return False
        
        # 处理键路径
        if isinstance(key_path, str):
            keys = key_path.split('.')
        else:
            keys = key_path
        
        current = self.data
        try:
            # 遍历到目标键
            for key in keys:
                if isinstance(current, dict):
                    current = current[key]
                elif isinstance(current, list):
                    current = current[int(key)]
                else:
                    return False
            
            # 添加元素
            if isinstance(current, list):
                current.append(value)
                return True
            return False
        except (KeyError, IndexError, ValueError):
            return False
    
    def get_json_type(self) -> str:
        """
        获取JSON根元素类型

        :return: 类型字符串 ('object', 'array', 'string', 'number', 'boolean', 'null')
        """
        if self.data is None:
            return 'null'
        
        if isinstance(self.data, dict):
            return 'object'
        elif isinstance(self.data, list):
            return 'array'
        elif isinstance(self.data, str):
            return 'string'
        elif isinstance(self.data, bool):
            return 'boolean'
        elif self.data is None:
            return 'null'
        else:
            return 'number'
    
    def get_json_info(self) -> Dict[str, Any]:
        """
        获取JSON信息

        :return: JSON信息字典
        """
        if self.data is None:
            return {
                'type': 'null',
                'size': 0,
                'depth': 0
            }
        
        def _calculate_depth(obj, current_depth=0):
            if isinstance(obj, dict):
                if not obj:
                    return current_depth + 1
                return max(_calculate_depth(v, current_depth + 1) for v in obj.values())
            elif isinstance(obj, list):
                if not obj:
                    return current_depth + 1
                return max(_calculate_depth(item, current_depth + 1) for item in obj)
            else:
                return current_depth + 1
        
        return {
            'type': self.get_json_type(),
            'size': len(json.dumps(self.data, ensure_ascii=False)),
            'depth': _calculate_depth(self.data)
        }
    
    def merge_json(self, other: Union[str, 'JsonUtils', Dict]) -> None:
        """
        合并另一个JSON数据

        :param other: 另一个JSON字符串、JsonUtils实例或字典
        """
        if self.data is None:
            self.data = {}
        
        if isinstance(other, str):
            other_data = json.loads(other)
        elif isinstance(other, JsonUtils):
            other_data = other.data
        else:
            other_data = other
        
        if isinstance(self.data, dict) and isinstance(other_data, dict):
            self.data.update(other_data)
        else:
            self.data = other_data
    
    def pretty_print(self) -> None:
        """
        美化打印JSON数据
        """
        if self.data is not None:
            print(self.to_string(2))
    
    @staticmethod
    def is_valid_json(json_str: str) -> bool:
        """
        检查字符串是否为有效的JSON

        :param json_str: JSON字符串
        :return: 是否有效
        """
        try:
            json.loads(json_str)
            return True
        except json.JSONDecodeError:
            return False
    
    @staticmethod
    def from_dict(data: Dict) -> 'JsonUtils':
        """
        从字典创建JsonUtils实例

        :param data: 字典数据
        :return: JsonUtils实例
        """
        json_utils = JsonUtils()
        json_utils.data = data
        return json_utils
    
    @staticmethod
    def create_empty_object() -> 'JsonUtils':
        """
        创建空的JSON对象

        :return: JsonUtils实例
        """
        return JsonUtils.from_dict({})
    
    @staticmethod
    def create_empty_array() -> 'JsonUtils':
        """
        创建空的JSON数组

        :return: JsonUtils实例
        """
        return JsonUtils.from_dict([])